using System;
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

[RequireComponent(typeof(MeshRenderer), typeof(BoxCollider), typeof(Rigidbody))]
public class MainLine : MonoBehaviour, IResettable
{
    [DataMember, SerializeField] private float speed = 3;
    [DataMember, SerializeField] private Color color;
    [DataMember] private MeshRenderer m_meshRenderer;
    [DataMember] private BoxCollider m_boxCollider;
    [DataMember] private Transform m_transform;
    [DataMember] private Rigidbody m_rb;
    private const float LandingTolerance = 0.001f;


    [DataMember] private readonly List<Collider> m_colliders = new List<Collider>();
    public bool Landed => m_colliders.Any() && Rigidbody.velocity.y <= LandingTolerance;

    public MeshRenderer MeshRenderer
    {
        get
        {
            if (m_meshRenderer) return m_meshRenderer;
            m_meshRenderer = GetComponent<MeshRenderer>();
            return m_meshRenderer;
        }
    }

    public BoxCollider BoxCollider
    {
        get
        {
            if (m_boxCollider) return m_boxCollider;
            m_boxCollider = GetComponent<BoxCollider>();
            return m_boxCollider;
        }
    }

    public Rigidbody Rigidbody
    {
        get
        {
            if (m_rb) return m_rb;
            m_rb = GetComponent<Rigidbody>();
            return m_rb;
        }
    }

    [DataMember] public float Speed
    {
        get => speed;
        set => speed = Mathf.Clamp(value, 0, Mathf.Infinity);
    }

    [DataMember] public Color Color
    {
        get => color;
        set
        {
            color = value;
#if UNITY_EDITOR
            if (EditorApplication.isPlaying)
            {
                MeshRenderer.material.color = color;
            }
            else
            {
                MeshRenderer.sharedMaterial.color = color;
            }
#else
                MeshRenderer.material.color = color;
#endif
        }
    }
    
    public LineEventArgs GetLineEventArgs()
    {
        return new LineEventArgs(m_transform.position);
    }


    private void OnCollisionEnter(Collision other)
    {
        m_colliders.Add(other.collider);
    }

    private void OnCollisionExit(Collision other)
    {
        m_colliders.Remove(other.collider);
    }

    private void Awake()
    {
        DebugManager.DoLog = true;
        DebugManager.DoLogWarning = true;
        DebugManager.DoLogError = true;
        m_transform = transform;
    }

    [DebugManager.CriticalDelegate]
    private void Run(InputManager.KeyType keyType)
    {
        if (keyType != InputManager.KeyType.Down) return;
        Singleton<GameController>.Instance.StartGame();
        Singleton<InputManager>.Instance.RemoveMouse(0, Run);
    }

    private void Start()
    {
        BindKeys();
        DebugManager.CurrentPriority = 0;
        this.SaveData();
    }

    private void BindKeys()
    {
        Singleton<InputManager>.Instance.BindMouse(0, Run);
        Singleton<InputManager>.Instance.Bind(KeyCode.R, state =>
        {
            if (state == InputManager.KeyType.Down)
            {
                Singleton<GameController>.Instance.ResetGame();
            }
        });
    }

    public void Reset()
    {
        BindKeys();
        if (!this.SetData())
        {
            DebugManager.LogError("Errors occurred when MainLine attempted to reload data");
        }
    }
}

public class LineEventArgs : EventArgs
{
    public readonly Vector3 position;
    public bool doCancel;
    public Action onEventCanceled;

    public LineEventArgs(Vector3 position)
    {
        this.position = position;
        doCancel = false;
    }
}